/*********************************************************************************
  *Copyright (c)    2021   xldeng
  *FileName:        config.cc.c
  *Author:          xldeng
  *Version:         1.0
  *Date:            2021/2/27 9:31
  *Description:     配置模块
  *Others:
  *Function List:
     1.…………
  *History:
     1.Date:
       Author:
       Modification:
**********************************************************************************/
#include "config.h"
#include "util.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
namespace sylar {
    static sylar::Logger::ptr g_logger = SYLAR_LOG_NAME("system");


    ConfigVarBase::ptr Config::LookupBase(const std::string &name) {
        RWMutexType::ReadLock lock(GetMutex());
        auto it = GetDatas().find(name);
        return it == GetDatas().end() ? nullptr : it->second;
    }
//"A.B", 10
//A:
//  B: 10
//  C: str
    /*
     *  解析node,将prefix和对应的node放入output中
     *  如果node含有map节点，对其递归调用，并加上先前的prefix
     */
    static void ListAllMember(const std::string &prefix,
                              const YAML::Node &node,
                              std::list<std::pair<std::string, const YAML::Node>> &output) {
        if (prefix.find_first_not_of("abcdefghikjlmnopqrstuvwxyz._012345678") != std::string::npos) {
            SYLAR_LOG_ERROR(SYLAR_LOG_ROOT()) << "Config invalid name: " << prefix << " : " << node;
            return;
        }
        output.emplace_back(prefix, node);
        if (node.IsMap()) {
            for (auto it = node.begin(); it != node.end(); it++) {
                ListAllMember(prefix.empty() ? it->first.Scalar() : prefix + "." + it->first.Scalar(),
                              it->second, output);
            }
        }
    }

    void Config::LoadFromYaml(const YAML::Node &root) {
        std::list<std::pair<std::string, const YAML::Node>> all_nodes;
        ListAllMember("", root, all_nodes);
        for (auto &i : all_nodes) {
            std::string key = i.first;
            if (key.empty()) {
                continue;
            }
            std::transform(key.begin(), key.end(), key.begin(), ::tolower);
            ConfigVarBase::ptr var = LookupBase(key);
            if (var) {
                if (i.second.IsScalar()) {
                    var->fromString(i.second.Scalar());
                } else {
                    std::stringstream ss;
                    ss << i.second;
                    var->fromString(ss.str());
                }
            }
        }
    }

    void Config::Visit(std::function<void(ConfigVarBase::ptr)> cb) {
        RWMutexType::ReadLock lock(GetMutex());
        ConfigVarMap &m = GetDatas();
        for (auto & it : m){
            cb(it.second);
        }
    }

}
